package com.common.aes;


import cn.hutool.core.util.HexUtil;
import com.common.cipher.ICipher;
import com.common.json.JsonUtil;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.Security;

/**
 * @author ZhangHaiWen
 * @title: AESUtils
 * @projectName minipasscheck
 * @description: AES加密，解密 方法
 * @date 2021/2/516:04
 */
public class AESImple implements ICipher {

    // 加密方式
    private static final String KEY_ALGORITHM = "AES";
    // 默认的加密算法
    private static final String DEFAULT_CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
    // 偏移量 前后端约定 不可修改 16位
    private static final String OFFSET = "6cb17440dff5557f";


    private volatile static AESImple aesImple;

    private AESImple(){

    }

    public static AESImple getInstance(){
        if(aesImple == null){
            synchronized (AESImple.class){
                if(aesImple == null){
                    aesImple = new AESImple();
                    // 支持PKCS7Padding加密
                    Security.addProvider(new BouncyCastleProvider());
                }
            }
        }
        return aesImple;
    }


    /**
     * AES 加密操作
     *
     * @param content  待加密内容
     * @param password 加密密码
     * @return 返回Base64转码后的加密数据
     */
    @Override
    public String encrypt(Object content, String password) {
        try {
            // 创建密码器
            Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
            byte[] byteContent = JsonUtil.toString(content).getBytes(StandardCharsets.UTF_8);
            //使用CBC模式，需要一个向量iv，可增加加密算法的强度
            IvParameterSpec iv = new IvParameterSpec(OFFSET.getBytes(StandardCharsets.UTF_8));
            // 初始化为加密模式的密码器
            cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(password),iv);
            // 加密
            byte[] result = cipher.doFinal(byteContent);
            //通过16进制转码返回
            return parseByte2HexStr(result);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return null;
    }

    /**
     * AES 解密操作
     *
     * @param content
     * @param password
     * @Param clazz
     * @return
     */
    @Override
    public <T> T decrypt(String content, String password,Class<T> clazz) {
        String decrypt = decrypt(content, password);
        return JsonUtil.parse(decrypt,clazz);
    }

    /**
     * AES 解密操作
     *
     * @param content
     * @param password
     * @return
     */
    @Override
    public String decrypt(String content, String password) {
        try {
            //实例化
            Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
            //使用CBC模式，需要一个向量iv，可增加加密算法的强度
            IvParameterSpec iv = new IvParameterSpec(OFFSET.getBytes(StandardCharsets.UTF_8));
            //使用密钥初始化，设置为解密模式
            cipher.init(Cipher.DECRYPT_MODE, getSecretKey(password),iv);
            //16进制转为2进制 执行操作
            //byte[] result = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
            byte[] result = cipher.doFinal(parseHexStr2Byte(content));
            return  new String(result, StandardCharsets.UTF_8);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    /**
     * 将16进制转换为二进制
     *
     * @param hexStr
     * @return
     */
    private static byte[] parseHexStr2Byte(String hexStr) {
        return HexUtil.decodeHex(hexStr);
    }

    /**
     * 将二进制转换成16进制
     *
     * @param buf
     * @return
     */
    public static String parseByte2HexStr(byte[] buf) {
        return HexUtil.encodeHexStr(buf);
    }

    /**
     * 生成加密秘钥
     *
     * @return
     */
    private static SecretKeySpec getSecretKey(String password) {
        // 转换为AES专用密钥
        return new SecretKeySpec(password.getBytes(StandardCharsets.UTF_8), KEY_ALGORITHM);
    }


    /*public static void main(String[] args) throws Exception{
        AESImple aesImple = AESImple.getInstance();
        String encrypt = aesImple.encrypt("o29oT5XbCRtPNJlinmZmLLQ8cC-M", "cfa0aac7c9316eca");
        String decrypt1 = aesImple.decrypt(encrypt, "cfa0aac7c9316eca");
        System.out.println(encrypt);
        System.out.println(decrypt1);

        //String decrypt2 = aesImple.decrypt("a6896948391af2460faffbe73d8998751d978608a46369a4c499fac7aa42224b", "cfa0aac7c9316eca");
        //System.out.println(decrypt2);
    }*/
}
